﻿using Essensoft.Paylink.Alipay;
using Essensoft.Paylink.Alipay.Domain;
using Essensoft.Paylink.Alipay.Notify;
using Essensoft.Paylink.Alipay.Request;
using Pay.DTO;

namespace Pay.Services.Imp
{
	/// <summary>
	/// 支付宝支付服务
	/// </summary>
	partial class PayService
	{
		/// <summary>
		/// 消费者扫二维码支付
		/// </summary>
		private async Task AliPayQRCodeAsync(PayRequestDto payReq, LayuiResultDto<PayResponseDto> result)
		{
			var model = new AlipayTradePrecreateModel
			{
				OutTradeNo = payReq.OutTradeNo,
				Subject = payReq.Description,
				TotalAmount = payReq.Amount.ToString("f2"),
				Body = payReq.Attach,
			};
			var req = new AlipayTradePrecreateRequest();
			req.SetBizModel(model);
            payReq.NotifyUrl = $"{payReq.BaseUrl}/Notify/AliQRCode";
            req.SetNotifyUrl(payReq.NotifyUrl);
			var rep = string.IsNullOrWhiteSpace(_payConfig.AlipayOption.AlipayPublicKey) ? await _alipayClient.CertificateExecuteAsync(req, _payConfig.AlipayOption)
				: await _alipayClient.ExecuteAsync(req, _payConfig.AlipayOption);
			if (rep.IsError)
			{
				result.Code = 10000;
				result.Msg = rep.Msg;
			}
			else
				result.Data.Result = rep.QrCode;
		}

		/// <summary>
		/// 商家扫二维码支付
		/// </summary>
		private async Task AliPayPassiveQRCodeAsync(PayRequestDto payReq, LayuiResultDto<PayResponseDto> result)
		{
			var model = new AlipayTradePayModel
			{
				OutTradeNo = payReq.OutTradeNo,
				Subject = payReq.Description,
				Scene = payReq.Scene,
				AuthCode = payReq.AuthCode,
				TotalAmount = payReq.Amount.ToString("f2"),
				Body = payReq.Attach
			};
			var req = new AlipayTradePayRequest();
			req.SetBizModel(model);
            var rep = string.IsNullOrWhiteSpace(_payConfig.AlipayOption.AlipayPublicKey) ? await _alipayClient.CertificateExecuteAsync(req, _payConfig.AlipayOption)
                : await _alipayClient.ExecuteAsync(req, _payConfig.AlipayOption);
            if (rep.IsError)
			{
				result.Code = 10000;
				result.Msg = rep.Msg;
			}
			else
				result.Data.Result = rep.Body;
		}

		/// <summary>
		/// PC端网页支付
		/// </summary>
		private async Task AliPayPCWebAsync(PayRequestDto payReq, LayuiResultDto<PayResponseDto> result)
		{
			var model = new AlipayTradePagePayModel
			{
				OutTradeNo = payReq.OutTradeNo,
				Subject = payReq.Description,
				ProductCode = payReq.ProductCode,
				TotalAmount = payReq.Amount.ToString("f2"),
				Body = payReq.Attach
			};
			var req = new AlipayTradePagePayRequest();
			req.SetBizModel(model);
            payReq.NotifyUrl = $"{payReq.BaseUrl}/Notify/AliPcWeb";
            req.SetNotifyUrl(payReq.NotifyUrl);
			req.SetReturnUrl(payReq.ReturnUrl);
			var rep = await _alipayClient.PageExecuteAsync(req, _payConfig.AlipayOption);
			if (rep.IsError)
			{
				result.Code = 10000;
				result.Msg = rep.Msg;
			}
			else
				result.Data.Result = rep.Body;
		}

		/// <summary>
		/// 移动端网页支付
		/// </summary>
		private async Task AliPayMobileWebAsync(PayRequestDto payReq, LayuiResultDto<PayResponseDto> result)
		{
			var model = new AlipayTradeWapPayModel
			{
				OutTradeNo = payReq.OutTradeNo,
				Subject = payReq.Description,
				ProductCode = payReq.ProductCode,
				TotalAmount = payReq.Amount.ToString("f2"),
				Body = payReq.Attach
			};
			var req = new AlipayTradeWapPayRequest();
			req.SetBizModel(model);
            payReq.NotifyUrl = $"{payReq.BaseUrl}/Notify/AliMobileWeb";
            req.SetNotifyUrl(payReq.NotifyUrl);
			req.SetReturnUrl(payReq.ReturnUrl);
			var rep = await _alipayClient.PageExecuteAsync(req, _payConfig.AlipayOption);
			if (rep.IsError)
			{
				result.Code = 10000;
				result.Msg = rep.Msg;
			}
			else
				result.Data.Result = rep.Body;
		}

		/// <summary>
		/// 移动应用APP支付
		/// </summary>
		private async Task AliPayAppAsync(PayRequestDto payReq, LayuiResultDto<PayResponseDto> result)
		{
			var model = new AlipayTradeAppPayModel
			{
				OutTradeNo = payReq.OutTradeNo,
				Subject = payReq.Description,
				TotalAmount = payReq.Amount.ToString("f2"),
				ProductCode = payReq.ProductCode,
				Body = payReq.Attach,
			};
			var req = new AlipayTradeAppPayRequest();
			req.SetBizModel(model);
			payReq.NotifyUrl = $"{payReq.BaseUrl}/Notify/AliApp";
			req.SetNotifyUrl(payReq.NotifyUrl);
			// 将response.Body给 ios、android端，由其去完成调起支付宝APP。
			// 客户端 Android 集成流程: https://opendocs.alipay.com/open/204/105296/
			// 客户端 iOS 集成流程: https://opendocs.alipay.com/open/204/105295/
			var rep = await _alipayClient.SdkExecuteAsync(req, _payConfig.AlipayOption);
			if (rep.IsError)
			{
				result.Code = 10000;
				result.Msg = rep.Msg;
			}
			else
				result.Data.Result = rep.Body;
		}

		/// <summary>
		/// 退款
		/// </summary>
		private async Task AliRefundAsync(RefundRequestDto refundReq, LayuiResultDto<RefundResponseDto> result)
		{
            var model = new AlipayTradeRefundModel
            {
                OutTradeNo = refundReq.OutTradeNo,
                RefundAmount = refundReq.RefundAmount.ToString("f2"),
                OutRequestNo = refundReq.RefundNo,
                RefundReason = refundReq.Reason				
            };
            var req = new AlipayTradeRefundRequest();
            req.SetBizModel(model);
			req.SetNotifyUrl(refundReq.NotifyUrl);
            var rep = string.IsNullOrWhiteSpace(_payConfig.AlipayOption.AlipayPublicKey) ? await _alipayClient.CertificateExecuteAsync(req, _payConfig.AlipayOption)
                : await _alipayClient.ExecuteAsync(req, _payConfig.AlipayOption);
            if (rep.IsError)
            {
                result.Code = 10000;
                result.Msg = rep.Msg;
            }
            else
                result.Data.Result = rep.Body;
        }

		/// <summary>
		/// 扫码回调
		/// </summary>
        private async Task AliNotifyQRCodeAsync(NotifyResultDto result, HttpRequest request)
		{
			try
			{
				result.PaySource = PaySourceEnum.PassiveCode;
                var rep = string.IsNullOrWhiteSpace(_payConfig.AlipayOption.AlipayPublicKey)
                ? await _notifyAlipayClient.CertificateExecuteAsync<AlipayTradePrecreateNotify>(request, _payConfig.AlipayOption)
                : await _notifyAlipayClient.ExecuteAsync<AlipayTradePrecreateNotify>(request, _payConfig.AlipayOption);
				result.IsSuccess = rep.TradeStatus == AlipayTradeStatus.Success;
                result.AppId = rep.AppId;
                result.OutTradeNo = rep.OutTradeNo;
                result.PayId = rep.TradeNo;
                result.Amount = decimal.Parse(rep.TotalAmount);
                result.OrginalData = rep;
            }
            catch(Exception ex)
			{
				result.Exception = $"{ex.Message}|{ex.StackTrace}";
			}
        }

        /// <summary>
        /// app回调
        /// </summary>
        private async Task AliNotifyAppAsync(NotifyResultDto result, HttpRequest request)
        {
            try
            {
                result.PaySource = PaySourceEnum.App;
                var rep = string.IsNullOrWhiteSpace(_payConfig.AlipayOption.AlipayPublicKey)
                ? await _notifyAlipayClient.CertificateExecuteAsync<AlipayTradeAppPayNotify>(request, _payConfig.AlipayOption)
                : await _notifyAlipayClient.ExecuteAsync<AlipayTradeAppPayNotify>(request, _payConfig.AlipayOption);
                result.IsSuccess = rep.TradeStatus == AlipayTradeStatus.Success;
                result.AppId = rep.AppId;
                result.OutTradeNo = rep.OutTradeNo;
                result.PayId = rep.TradeNo;
                result.Amount = decimal.Parse(rep.TotalAmount);
                result.Attach = rep.PassbackParams;
                result.OrginalData = rep;
            }
            catch (Exception ex)
            {
                result.Exception = $"{ex.Message}|{ex.StackTrace}";
            }
        }

        /// <summary>
        /// PC网页回调
        /// </summary>
        private async Task AliNotifyPcWebAsync(NotifyResultDto result, HttpRequest request)
        {
            try
            {
                result.PaySource = PaySourceEnum.PCWeb;
                var rep = string.IsNullOrWhiteSpace(_payConfig.AlipayOption.AlipayPublicKey)
                ? await _notifyAlipayClient.CertificateExecuteAsync<AlipayTradePagePayNotify>(request, _payConfig.AlipayOption)
                : await _notifyAlipayClient.ExecuteAsync<AlipayTradePagePayNotify>(request, _payConfig.AlipayOption);
                result.IsSuccess = rep.TradeStatus == AlipayTradeStatus.Success;
                result.AppId = rep.AppId;
                result.OutTradeNo = rep.OutTradeNo;
                result.RefundNo = rep.OutBizNo;
                result.PayId = result.NotifyType == "Pay" ? rep.TradeNo : "";
                result.RefundId = result.NotifyType == "Refund" ? rep.TradeNo : "";
                result.Amount = !string.IsNullOrWhiteSpace(rep.TotalAmount) ? decimal.Parse(rep.TotalAmount) : 0;
                result.RefundAmount = !string.IsNullOrWhiteSpace(rep.RefundFee) ? decimal.Parse(rep.RefundFee) : 0;
                result.PayId = rep.TradeNo;
                result.Amount = decimal.Parse(rep.TotalAmount);
                result.Attach = rep.PassbackParams;
                result.OrginalData = rep;
            }
            catch (Exception ex)
            {
                result.Exception = $"{ex.Message}|{ex.StackTrace}";
            }
        }

        /// <summary>
        /// 移动网页回调
        /// </summary>
        private async Task AliNotifyMobileWebAsync(NotifyResultDto result, HttpRequest request)
        {
            try
            {
                result.PaySource = PaySourceEnum.MobileWeb;
                var rep = string.IsNullOrWhiteSpace(_payConfig.AlipayOption.AlipayPublicKey)
                ? await _notifyAlipayClient.CertificateExecuteAsync<AlipayTradeWapPayNotify>(request, _payConfig.AlipayOption)
                : await _notifyAlipayClient.ExecuteAsync<AlipayTradeWapPayNotify>(request, _payConfig.AlipayOption);
                result.IsSuccess = rep.TradeStatus == AlipayTradeStatus.Success;
                result.AppId = rep.AppId;
                result.OutTradeNo = rep.OutTradeNo;
				result.PayId = rep.TradeNo;
				result.Amount = decimal.Parse(rep.TotalAmount);
                result.Attach = rep.PassbackParams;
                result.OrginalData = rep;
            }
            catch (Exception ex)
            {
                result.Exception = $"{ex.Message}|{ex.StackTrace}";
            }
        }
    }
}
